package com.free.semantic.core.impl;

import com.free.semantic.common.*;
import com.free.semantic.core.ConceptManage;
import com.free.semantic.core.concept.SubConceptManage;
import com.free.semantic.exception.SystemException;
import com.free.semantic.facade.Link;
import com.free.semantic.facade.Node;
import com.free.semantic.req.RelaItemDef;
import com.free.semantic.req.RelationDefine;
import com.free.semantic.utils.Utils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.free.semantic.common.Range.ONE;
import static com.free.semantic.core.concept.SubConceptManage.getConceptLs;
import static com.free.semantic.core.concept.impl.ConceptSelfInfoConcept.FIND_ONE;
import static com.free.semantic.utils.Utils.isMulti;

public class ConceptManageImpl implements ConceptManage {

    protected final Map<String, RelationDefine> relationDefineMap = new HashMap<>();

    /**
     * 事物名称到唯一名称的映射
     */
    private final Map<String, List<String>> objectAliasMap = new HashMap<>();

    /**
     * 唯一名称到事物信息的映射
     */
    protected final Map<String, ObjectInfo> objectInfoMap = new LinkedHashMap<>();

    protected final Map<String, List<RelationInstance>> relationInstanceMap = new HashMap<>();

    protected final Map<Integer, RelationInstance> instanceMap = new HashMap<>();

    protected final Map<String, Map<String, List<RelationItem>>> fromObjRelation = new HashMap<>();

    protected final Map<String, Map<String, List<RelationItem>>> destObjRelation = new HashMap<>();

    private int currentInstanceId = 1;

    private final AtomicInteger currentObjectId = new AtomicInteger(0);

    private static final String SPLIT = ":";

    private final AtomicInteger currentVersion = new AtomicInteger(1);

    private final List<Integer> allVersionList = Ls.of(1);

    public ConceptManageImpl() {
        SubConceptManage.appendSubConcept(this);
    }

    @Override
    public void addConcept(String... thingName) {
        for (String instanceName : thingName) {
            if (StringUtils.isBlank(instanceName)) {
                throw new IllegalArgumentException("事物名称为空");
            }
            addConcept(instanceName);
        }
        sortObjectList();
    }

    @Override
    public int getLastVersion() {
        return currentVersion.get();
    }

    @Override
    public int increaseVersion() {
        int version = currentVersion.incrementAndGet();
        allVersionList.add(version);
        return version;
    }

    @Override
    public void conceptMergeTo(List<String> sourceFrom, String destFrom, List<String> sourceTo, String destTo) {
        if (sourceFrom == null || sourceTo == null) {
            throw new IllegalArgumentException();
        }
        if (CollectionUtils.isEmpty(sourceFrom) || CollectionUtils.isEmpty(sourceTo)) {
            throw new IllegalArgumentException();
        }
        if (sourceFrom.size() != sourceTo.size()) {
            throw new IllegalArgumentException("合并概念源链来源事物数量 与 合并概念目标链 来源事物数量不一致");
        }

        sourceFrom = sourceFrom.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        destFrom = getObjUniqueId(destFrom);

        sourceTo = sourceTo.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        destTo = getObjUniqueId(destTo);

        Map<String, String> sourceNameMap = new HashMap<>();

        for (int i = 0; i < sourceFrom.size(); i++) {
            String sourceFromName = sourceFrom.get(i);
            String sourceToName = sourceTo.get(i);
            sourceNameMap.put(sourceFromName, sourceToName);
        }
        sourceNameMap.put(destFrom, destTo);

        List<RelationChain> fromRelationChain = buildExactRelationChainInner(sourceFrom, destFrom);
        if (fromRelationChain.size() != 1) {
            throw new RuntimeException(String.format("路径指代不明，来源事物为：%s,目标事物为：%s 的关系路径数量不为1", sourceFrom, destFrom));
        }
        List<RelationItem> items = fromRelationChain.get(0).getRelationItems();
        if (items.size() != 1) {
            throw new RuntimeException("不允许跨关系进行概念融合");
        }
        RelationItem fromItem = items.get(0);

        List<RelationChain> toRelationChain = buildExactRelationChainInner(sourceTo, destTo);
        if (toRelationChain.size() != 1) {
            throw new RuntimeException(String.format("路径指代不明，来源事物为：%s,目标事物为：%s 的关系路径数量不为1", sourceFrom, destFrom));
        }
        RelationItem toItem = toRelationChain.get(0).toRelationItem();

        for (RangeObj rangeObj : fromItem.getSourceObjectList()) {
            Range fromRange = rangeObj.getRange();
            String toName = sourceNameMap.get(rangeObj.getObjectName());
            Range toRange = toItem.getObjectRange(toName);
            if (!fromRange.equals(toRange)) {
                throw new RuntimeException(String.format("关系链中，事物%s 与事物%s 数量范围不一致", getRawName(rangeObj.getObjectName()), getRawName(toName)));
            }
        }

        if (!fromItem.getDestObject().getRange().equals(toItem.getDestObject().getRange())) {
            throw new RuntimeException(String.format("关系链中，事物%s 与事物%s 数量范围不一致", getRawName(fromItem.getDestObject().getObjectName()), getRawName(toItem.getDestObject().getObjectName())));
        }

        Map<String, String> waitToAddRelation = new HashMap<>();

        for (RangeObj rangeObj : fromItem.getSourceObjectList()) {
            String fromName = rangeObj.getObjectName();
            String toName = sourceNameMap.get(rangeObj.getObjectName());
            buildNotLinkMap(waitToAddRelation, fromName, toName);
            buildNotLinkMap(waitToAddRelation, toName, fromName);
        }

        String fromName = toItem.getDestObj();
        String toName = fromItem.getDestObj();
        buildNotLinkMap(waitToAddRelation, fromName, toName);
        buildNotLinkMap(waitToAddRelation, toName, fromName);

        synchronized (this) {
            removeRelationItemInner(fromItem);
            for (Map.Entry<String, String> entry : waitToAddRelation.entrySet()) {
                Utils.createRelation(this, FIND_ONE, getRawName(entry.getKey()), getRawName(entry.getValue()));
            }
        }
    }

    private void buildNotLinkMap(Map<String, String> waitToAddRelation, String fromName, String toName) {
        List<RelationChain> relationChains = buildExactRelationChainInner(Ls.of(fromName), toName);
        if (CollectionUtils.isEmpty(relationChains)) {
            waitToAddRelation.put(fromName, toName);
            return;
        }
        if (relationChains.size() > 1) {
            throw new RuntimeException(String.format("来源事物%s与目标事物%s之间，关系链超过1条", getRawName(fromName), getRawName(toName)));
        }
        RelationItem relationItem = relationChains.get(0).toRelationItem();
        if (!relationItem.getSourceObjectList().get(0).getRange().equals(ONE) || !relationItem.getDestObject().getRange().equals(ONE)) {
            throw new RuntimeException(String.format("来源事物%s与目标事物%s之间，关系不是1比1", getRawName(fromName), getRawName(toName)));
        }
    }

    @Override
    @Deprecated
    public synchronized void addRelationDefine(String relationName, List<RelaItemDef> relaItemDefines) {
        if (StringUtils.isBlank(relationName)) {
            throw new IllegalArgumentException("关系名称不能为空");
        }
        if (relationDefineMap.containsKey(relationName)) {
            throw new IllegalArgumentException(String.format("已经存在关系名称为%s的关系", relationName));
        }
        if (!relaItemDefines.isEmpty()) {
            relaItemDefines.get(0).setName(relationName);
        }
        if (relaItemDefines.size() == 2) {
            relaItemDefines.get(1).setName("被" + relationName);
        }
        RelationDefine relationDefine = new RelationDefine();
        relationDefine.setName(relationName);
        relationDefine.setRelaItemDefs(relaItemDefines);
        relationDefineMap.put(relationName, relationDefine);
    }

    @Override
    public boolean instanceRelation(String relationName, Map<String, String> objNameMap) {
        if (!relationDefineMap.containsKey(relationName)) {
            throw new IllegalArgumentException(String.format("不存在名为%s的关系", relationName));
        }
        RelationDefine relationDefine = relationDefineMap.get(relationName);
        Map<String, String> uniqueIdMap = replaceToUniqueId(objNameMap);
        RelationInstance instance = relationDefine.buildRelationInstance(uniqueIdMap, this);
        return addInstance(instance);
    }

    /**
     * @param relationItems
     * @return
     */
    @Override
    public boolean instanceRelation(List<RelationItem> relationItems) {
        for (RelationItem item : relationItems) {
            item = item.clone();
            RelationInstance instance = new RelationInstance(item.getName());
            instance.setRelationItems(Ls.of(item));
            item.setParentInstance(instance);
            transferToLocatorName(item);
            boolean success = addInstance(instance);
            if (!success) {
                return false;
            }
        }
        return true;
    }

    private Map<String, String> replaceToUniqueId(Map<String, String> objNameMap) {
        Map<String, String> result = new HashMap<>();
        for (Map.Entry<String, String> entry : objNameMap.entrySet()) {
            String variableName = entry.getKey();
            String locator = entry.getValue();
            String objUniqueId = getObjUniqueIdWithCreate(locator);
            result.put(variableName, objUniqueId);
        }
        return result;
    }

    private String getObjUniqueIdWithCreate(String locateExpress) {
        if (StringUtils.isBlank(locateExpress)) {
            throw new IllegalArgumentException("对象定位表达式为空");
        }
        if (locateExpress.startsWith("object ")) {
            String[] createExpress = locateExpress.split(" ");
            if (createExpress.length != 2) {
                throw new RuntimeException(String.format("创建对象表达 %s 错误", locateExpress));
            }
            return addConcept(createExpress[1]);
        }
        return getObjUniqueId(locateExpress);
    }

    private String getObjUniqueId(String locateExpress) {
        String[] split = locateExpress.split(SPLIT);
        String lastUniqueId = null;
        if (split.length >= 1) {
            String rawName = split[0];
            if (objectAliasMap.containsKey(rawName)) {
                if (objectAliasMap.get(rawName).size() == 1) {
                    lastUniqueId = objectAliasMap.get(rawName).get(0);
                } else {
                    throw new RuntimeException(String.format("对象定位表达式 %s 无法定位具体某一个对象", locateExpress));
                }
            } else {
                throw new RuntimeException(String.format("对象定位表达式 %s 错误", locateExpress));
            }
        }
        if (split.length == 1) {
            return lastUniqueId;
        }
        for (int i = 1; i < split.length; i++) {
            String current = split[i];
            List<String> allPossible = objectAliasMap.get(current);

            List<String> tempLastUnique = new ArrayList<>();
            for (String s : allPossible) {
                List<RelationChain> relationChains = buildAllRelationChainInner(Ls.of(lastUniqueId), s);
                if (relationChains.size() > 1) {
                    throw new RuntimeException(String.format("对象定位表达式 %s 无法定位具体某一个对象", locateExpress));
                }
                if (relationChains.isEmpty()) {
                    continue;
                }
                tempLastUnique.add(s);
            }
            if (tempLastUnique.size() == 1) {
                lastUniqueId = tempLastUnique.get(0);
            } else {
                throw new RuntimeException(String.format("对象定位表达式 %s 无法定位具体某一个对象", locateExpress));
            }
        }
        return lastUniqueId;
    }

    private String getLocateExpress(String uniqueId) {
        String rawName = getRawName(uniqueId);
        if (isRawNameUnique(uniqueId)) {
            return rawName;
        } else {

            Set<String> foundWay = new HashSet<>();
            List<String> currentPath = Ls.of(uniqueId);
            List<String> uniqueIdPath = buildUniqueIdWay(foundWay, currentPath, uniqueId);

            List<String> path = uniqueIdPath.stream().map(this::getRawName).collect(Collectors.toList());
            if (path.isEmpty()) {
                throw new RuntimeException("唯一表达式路径构建失败");
            }
            String[] pathArray = path.toArray(new String[0]);
            CollectionUtils.reverseArray(pathArray);
            return String.join(SPLIT, pathArray);
        }
    }

    private List<String> buildUniqueIdWay(Set<String> foundWay, List<String> currentPath, String currentUniqueId) {
        Map<String, List<RelationItem>> fromRelationLs = destObjRelation.getOrDefault(currentUniqueId, new HashMap<>());

        List<RelationItem> itemList = fromRelationLs.values().stream().flatMap(Collection::stream).collect(Collectors.toList());

        for (RelationItem relationItem : itemList) {

            for (RangeObj rangeObj : relationItem.getSourceObjectList()) {
                if (foundWay.contains(rangeObj.getObjectName())) {
                    continue;
                }
                if (isRawNameUnique(rangeObj.getObjectName())) {
                    currentPath.add(rangeObj.getObjectName());
                    return currentPath;
                } else {
                    ArrayList<String> arrayList = new ArrayList<>(currentPath);
                    arrayList.add(rangeObj.getObjectName());

                    HashSet<String> newSet = new HashSet<>(foundWay);
                    newSet.add(rangeObj.getObjectName());

                    List<String> result = buildUniqueIdWay(newSet, arrayList, rangeObj.getObjectName());

                    if (!result.isEmpty()) {
                        return result;
                    }
                }
            }
        }
        return new ArrayList<>();
    }

    private boolean isRawNameUnique(String uniqueId) {
        ObjectInfo objectInfo = objectInfoMap.get(uniqueId);
        String rawName = objectInfo.getRawName();
        List<String> rawNameLs = objectAliasMap.get(rawName);
        return rawNameLs.size() == 1;
    }

    private String getRawName(String uniqueId) {
        ObjectInfo objectInfo = objectInfoMap.get(uniqueId);
        return objectInfo.getRawName();
    }

    private boolean addInstance(RelationInstance instance) {
        boolean repeat = checkInstanceRepeat(instance);
        if (!repeat) {
            buildIndex(instance);
            instance.setInstanceID(getNewInstanceId());
            setVersion(instance, currentVersion.get());
            instanceMap.put(instance.getInstanceID(), instance);
            instance.setParentToNull();
            relationInstanceMap.get(instance.getName()).add(instance);
            safeCheckAll();
            return true;
        }
        return false;
    }

    private RelationItem findRelationItem(List<String> sourceObjList, String dest) {
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException("来源事物为空");
        }
        List<String> sourceObjListCopy = sourceObjList.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        String destCopy = getObjUniqueId(dest);
        String source = sourceObjListCopy.get(0);
        Map<String, List<RelationItem>> listMap = fromObjRelation.get(source);
        List<RelationItem> possible = listMap.get(destCopy);
        List<RelationItem> match = possible.stream().filter(item -> item.getSourceObjList().equals(sourceObjListCopy)
                && item.getDestObj().equals(destCopy)).collect(Collectors.toList());
        if (match.isEmpty()) {
            throw new IllegalArgumentException(String.format("不存在来源事物 %s，目标事物%s的关系 ", sourceObjList, dest));
        }
        if (match.size() > 1) {
            throw new SystemException(String.format("系统异常，存在多个来源事物 %s，目标事物%s的关系 ", sourceObjList, dest));
        }
        return match.get(0);
    }

    private void removeRelationItemInner(RelationItem relationItem) {
        int instanceID = relationItem.getParentInstanceID();
        synchronized (this) {
            RelationInstance instance = instanceMap.get(instanceID);
            boolean success = instance.removeRelationItem(relationItem);
            assert success;
            if (instance.getRelationItems().isEmpty()) {
                instanceMap.remove(instanceID);
                relationInstanceMap.get(instance.getName()).removeIf(ins -> ins.getInstanceID() == instanceID);
                if (relationInstanceMap.get(instance.getName()).isEmpty()) {
                    relationInstanceMap.remove(instance.getName());
                }
            }
            removeIndex(relationItem);
        }
    }

    @Override
    public void removeRelationItem(List<String> source, String dest) {
        RelationItem singleItem = Utils.findSingleItem(this, source, dest);
        removeRelation(singleItem);
    }

    @Override
    public void removeObject(List<String> objectName) {
        for (String object : objectName) {
            String uniqueId = getObjUniqueId(object);
            for (RelationItem relationItem : getGoRelationByObjectInner(uniqueId)) {
                removeRelationItemInner(relationItem);
            }
            for (RelationItem relationItem : getBackRelationByObjectInner(uniqueId)) {
                removeRelationItemInner(relationItem);
            }
            objectInfoMap.remove(uniqueId);
            objectAliasMap.get(object).remove(uniqueId);
            if (objectAliasMap.get(object).isEmpty()) {
                objectAliasMap.remove(object);
            }
        }
    }

    public void removeObject(String object) {
        String uniqueId = getObjUniqueId(object);
        if (fromObjRelation.containsKey(uniqueId) && !fromObjRelation.get(uniqueId).isEmpty()
                || destObjRelation.containsKey(uniqueId) && !destObjRelation.get(uniqueId).isEmpty()) {
            throw new RuntimeException(String.format("事物%s存在关联关系,无法移除", object));
        }
        objectInfoMap.remove(uniqueId);
        objectAliasMap.get(object).remove(uniqueId);
        if (objectAliasMap.get(object).isEmpty()) {
            objectAliasMap.remove(object);
        }
    }

    private void removeRelation(RelationItem relationItem) {
        RelationItem item = relationItem.clone();
        transferToLocatorName(item);
        removeRelationItemInner(item);
    }

    private void removeIndex(RelationItem relationItem) {
        for (String source : relationItem.getSourceObjList()) {
            String destObj = relationItem.getDestObj();
            assert fromObjRelation.containsKey(source);
            Map<String, List<RelationItem>> destMap = fromObjRelation.get(source);
            assert destMap.containsKey(destObj);
            boolean success = destMap.get(destObj).remove(relationItem);
            assert success;
            if (destMap.get(destObj).isEmpty()) {
                destMap.remove(destObj);
            }
            if (destMap.isEmpty()) {
                fromObjRelation.remove(source);
            }
            assert destObjRelation.containsKey(destObj);
            Map<String, List<RelationItem>> sourceMap = destObjRelation.get(destObj);
            assert sourceMap.containsKey(source);
            success = sourceMap.get(source).remove(relationItem);
            assert success;
            if (sourceMap.get(source).isEmpty()) {
                sourceMap.remove(source);
            }
            if (sourceMap.isEmpty()) {
                destObjRelation.remove(destObj);
            }
        }
    }

    private void setVersion(RelationInstance instance, int version) {
        for (RelationItem relationItem : instance.getRelationItems()) {
            relationItem.setVersion(version);
        }
    }

    private void safeCheckAll() {
        for (ObjectInfo from : objectInfoMap.values()) {
            if (!hasDifferentOutput(from.getName())) {
                continue;
            }
            for (ObjectInfo dest : objectInfoMap.values()) {
                if (from.getName().equals(dest.getName())) {
                    continue;
                }
                if (hasDifferentSource(dest.getName())) {
                    buildAllRelationChainInner(Ls.of(from.getName()), dest.getName());
                }
            }
        }
    }

    /**
     * 检查是否有重复的执行路径
     *
     * @param allPossible
     */
    private List<RelationChain> removeRepeat(String from, List<RelationChain> allPossible) {
        List<RelationChain> result = new ArrayList<>();
        Map<Set<String>, List<RelationChain>> listMap = allPossible.stream().collect(Collectors.groupingBy(aa -> aa.getUniquePathSet()));
        for (Map.Entry<Set<String>, List<RelationChain>> listEntry : listMap.entrySet()) {
            result.add(listEntry.getValue().get(0));
        }
        return result;
    }

    private boolean hasDifferentSource(String fromName) {
        if (!destObjRelation.containsKey(fromName)) {
            return false;
        }
        Map<String, List<RelationItem>> destMap = destObjRelation.get(fromName);
        List<Range> allRange = destMap.values().stream().flatMap(Collection::stream).map(relationItem -> relationItem.getSourceObjectList().stream().map(RangeObj::getRange).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList());
        if (allRange.size() <= 1) {
            return false;
        }
        allRange = allRange.stream().distinct().collect(Collectors.toList());
        return allRange.size() > 1 || allRange.get(0).equals(ONE);
    }

    private boolean hasDifferentOutput(String fromName) {
        if (!fromObjRelation.containsKey(fromName)) {
            return false;
        }
        Map<String, List<RelationItem>> destMap = fromObjRelation.get(fromName);
        List<Range> allRange = destMap.values().stream().flatMap(Collection::stream).map(relationItem -> relationItem.getDestObject().getRange()).collect(Collectors.toList());
        if (allRange.size() <= 1) {
            return false;
        }
        allRange = allRange.stream().distinct().collect(Collectors.toList());
        return allRange.size() > 1 || allRange.get(0).equals(ONE);
    }

    private void sortObjectList() {
        List<String> allObjectsList = new ArrayList<>(objectInfoMap.keySet());
        allObjectsList.sort(Comparator.naturalOrder());
        for (int i = 0; i < allObjectsList.size(); i++) {
            String objectName = allObjectsList.get(i);
            objectInfoMap.get(objectName).setListIndex(i);
        }
    }

    private synchronized String addConcept(String instanceName) {
        String uniqueObjName = getUniqueObjName(instanceName);
        objectInfoMap.put(uniqueObjName, new ObjectInfo(uniqueObjName, instanceName));
        if (!objectAliasMap.containsKey(instanceName)) {
            objectAliasMap.put(instanceName, Ls.of(uniqueObjName));
        } else {
            objectAliasMap.get(instanceName).add(uniqueObjName);
        }
        return uniqueObjName;
    }

    private boolean checkInstanceRepeat(RelationInstance relationInstance) {
        for (RelationItem relationItem : relationInstance.getRelationItems()) {
            RelationItem clone = relationItem.clone();
            RelationItem item = findSingleItemWithoutError(clone.getSourceObjList(), clone.getDestObj());
            if (item != null) {
                throw new RuntimeException(String.format("已经存在关系%s，重复添加", item));
            }
        }
        return false;
    }

    private RelationItem findSingleItemWithoutError(List<String> source, String dest) {
        List<RelationItem> match = new ArrayList<>();
        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.getOrDefault(source.get(0), new HashMap<>());
        List<RelationItem> itemList = relationItemMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
        for (RelationItem relationItem : itemList) {
            if (!relationItem.getDestObj().equals(dest)) {
                continue;
            }
            List<String> itemSourceObjList = relationItem.getSourceObjList();
            if (new HashSet<>(itemSourceObjList).equals(new HashSet<>(source))) {
                match.add(relationItem);
            }
        }
        if (match.size() != 1) {
            return null;
        }
        return match.get(0);
    }

    private void buildIndex(RelationInstance relationInstance) {
        if (!relationInstanceMap.containsKey(relationInstance.getName())) {
            relationInstanceMap.put(relationInstance.getName(), new ArrayList<>());
        }
        List<RelationItem> relationItems = relationInstance.getRelationItems();
        if (CollectionUtils.isEmpty(relationItems)) {
            return;
        }
        synchronized (this) {
            for (RelationItem relationItem : relationItems) {
                List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
                RangeObj destObjects = relationItem.getDestObject();
                for (RangeObj source : sourceObjectList) {
                    for (RangeObj destObject : Ls.of(destObjects)) {
                        if (!fromObjRelation.containsKey(source.getObjectName())) {
                            fromObjRelation.put(source.getObjectName(), new HashMap<>());
                        }
                        if (!fromObjRelation.get(source.getObjectName()).containsKey(destObject.getObjectName())) {
                            fromObjRelation.get(source.getObjectName()).put(destObject.getObjectName(), new ArrayList<>());
                        }
                        fromObjRelation.get(source.getObjectName()).get(destObject.getObjectName()).add(relationItem);
                        if (!destObjRelation.containsKey(destObject.getObjectName())) {
                            destObjRelation.put(destObject.getObjectName(), new HashMap<>());
                        }
                        if (!destObjRelation.get(destObject.getObjectName()).containsKey(source.getObjectName())) {
                            destObjRelation.get(destObject.getObjectName()).put(source.getObjectName(), new ArrayList<>());
                        }
                        destObjRelation.get(destObject.getObjectName()).get(source.getObjectName()).add(relationItem);
                    }
                }
            }
        }
    }

    @Override
    public List<RelationInstance> getAllInstance() {
        List<RelationInstance> instances = instanceMap.values().stream().map(RelationInstance::clone).collect(Collectors.toList());
        transferToRawNameInstance(instances);
        return instances;
    }

    @Override
    public List<String> getAllObjects() {
        return objectInfoMap.values().stream().map(ObjectInfo::getName).map(this::getLocateExpress).collect(Collectors.toList());
    }

    @Override
    public List<String> findAllRootObjectList() {
        List<String> result = new ArrayList<>();
        List<String> allObject = new ArrayList<>(objectInfoMap.keySet());
        while (CollectionUtils.isNotEmpty(allObject)) {
            String objectName = allObject.stream().findFirst().orElse("");
            if (StringUtils.isBlank(objectName)) {
                return result;
            }
            result.add(objectName);
            Set<String> found = new HashSet<>();
            found.add(objectName);
            findAllRelatedObj(found, objectName);
            allObject.removeAll(found);
        }
        result = result.stream().map(this::getLocateExpress).filter(concept -> !getConceptLs().contains(concept)).collect(Collectors.toList());
        return result;
    }

    private void findAllRelatedObj(Set<String> found, String current) {
        {
            Map<String, List<RelationItem>> relationItemMap = fromObjRelation.getOrDefault(current, new HashMap<>());
            for (RelationItem item : relationItemMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList())) {
                for (RangeObj rangeObj : item.getSourceObjectList()) {
                    if (!found.contains(rangeObj.getObjectName())) {
                        found.add(rangeObj.getObjectName());
                        findAllRelatedObj(found, rangeObj.getObjectName());
                    }
                }
                RangeObj rangeObj = item.getDestObject();
                if (!found.contains(rangeObj.getObjectName())) {
                    found.add(rangeObj.getObjectName());
                    findAllRelatedObj(found, rangeObj.getObjectName());
                }
            }
        }
        {
            Map<String, List<RelationItem>> relationItemMap = destObjRelation.getOrDefault(current, new HashMap<>());
            for (RelationItem item : relationItemMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList())) {
                for (RangeObj rangeObj : item.getSourceObjectList()) {
                    if (!found.contains(rangeObj.getObjectName())) {
                        found.add(rangeObj.getObjectName());
                        findAllRelatedObj(found, rangeObj.getObjectName());
                    }
                }
                RangeObj rangeObj = item.getDestObject();
                if (!found.contains(rangeObj.getObjectName())) {
                    found.add(rangeObj.getObjectName());
                    findAllRelatedObj(found, rangeObj.getObjectName());
                }
            }
        }
    }

    @Override
    public List<RelationItem> getGoRelationByObject(String name) {
        name = getObjUniqueId(name);
        if (!objectInfoMap.containsKey(name)) {
            return new ArrayList<>();
        }
        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.getOrDefault(name, new HashMap<>());
        return relationItemMap.values().stream().flatMap(Collection::stream).map(RelationItem::clone).map(this::transferToRawName).collect(Collectors.toList());
    }

    private List<RelationItem> getGoRelationByObjectInner(String name) {
        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.getOrDefault(name, new HashMap<>());
        return relationItemMap.values().stream().flatMap(Collection::stream).map(RelationItem::clone).collect(Collectors.toList());
    }

    @Override
    public List<RelationItem> getBackRelationByObject(String name) {
        name = getObjUniqueId(name);
        if (!objectInfoMap.containsKey(name)) {
            return new ArrayList<>();
        }
        Map<String, List<RelationItem>> relationItemMap = destObjRelation.getOrDefault(name, new HashMap<>());
        return relationItemMap.values().stream().flatMap(Collection::stream).map(RelationItem::clone).map(this::transferToRawName).collect(Collectors.toList());
    }

    private List<RelationItem> getBackRelationByObjectInner(String name) {
        Map<String, List<RelationItem>> relationItemMap = destObjRelation.getOrDefault(name, new HashMap<>());
        return relationItemMap.values().stream().flatMap(Collection::stream).map(RelationItem::clone).collect(Collectors.toList());
    }

    @Override
    public List<RelationInstance> getDirectRelationIns(String name) {
        name = getObjUniqueId(name);
        List<RelationItem> allRelation = getGoRelationByObjectInner(name);
        allRelation.addAll(getBackRelationByObjectInner(name));
        allRelation.forEach(this::transferToRawName);

        List<RelationInstance> instances = allRelation.stream().map(RelationItem::getParentInstanceID).distinct().map(instanceMap::get).filter(Objects::nonNull).collect(Collectors.toList());
        List<RelationInstance> instanceList = instances.stream().map(RelationInstance::clone).collect(Collectors.toList());
        transferToRawNameInstance(instanceList);

        return instanceList;
    }

    @Override
    public List<Node> getAllNode() {
        List<Node> result = new ArrayList<>();
        Set<String> conceptLs = getConceptLs();
        for (ObjectInfo value : objectInfoMap.values()) {
            if (conceptLs.contains(value.getRawName())) {
                continue;
            }
            Node node = new Node();
            node.setId(value.getName());
            node.setName(value.getRawName());
            result.add(node);
        }
        Set<String> registerId = new HashSet<>();
        for (RelationInstance instances : relationInstanceMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList())) {
            List<RelationItem> relationItems = instances.getRelationItems();
            for (RelationItem relationItem : relationItems) {
                List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
                if (conceptLs.containsAll(sourceObjectList.stream().map(aa -> getRawName(aa.getObjectName())).collect(Collectors.toList()))) {
                    continue;
                }
                if (sourceObjectList.size() == 1) {
                    continue;
                }
                String nodeId = getNodeId(relationItem);
                String nodeName = getNodeName(relationItem);
                if (registerId.add(nodeId)) {
                    Node node = new Node();
                    node.setId(nodeId);
                    node.setName(nodeName);
                    result.add(node);
                }
            }
        }
        return result;
    }

    private String getNodeId(RelationItem relationItem) {
        List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
        return String.join(" ", sourceObjectList.stream().map(aa -> aa.toString()).collect(Collectors.toList()));
    }

    private String getNodeName(RelationItem relationItem) {
        List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
        return String.join(" ", sourceObjectList.stream().map(aa -> aa.getRange().toString() + getRawName(aa.getObjectName())).collect(Collectors.toList()));
    }

    @Override
    public List<Link> getAllLink() {
        List<Link> result = new ArrayList<>();
        Set<String> conceptLs = getConceptLs();
        for (RelationInstance instances : relationInstanceMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList())) {
            List<RelationItem> relationItems = instances.getRelationItems();
            for (RelationItem relationItem : relationItems) {
                List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
                RangeObj destObject = relationItem.getDestObject();
                if (conceptLs.containsAll(sourceObjectList.stream().map(aa -> getRawName(aa.getObjectName())).collect(Collectors.toList()))) {
                    continue;
                }
                String nodeId = getNodeId(relationItem);
                Link link = new Link();
                link.setFrom(nodeId);
                link.setTo(destObject.getObjectName());
                result.add(link);
            }
        }
        return result;
    }

    @Override
    public List<RelationDefine> getAllRelationDefine() {
        return new ArrayList<>(relationDefineMap.values());
    }

    @Override
    public List<RelationInstance> getAllRelationInstance() {
        List<RelationInstance> instances = new ArrayList<>(instanceMap.values()).stream().map(RelationInstance::clone).collect(Collectors.toList());
        transferToRawNameInstance(instances);
        return instances;
    }

    @Override
    public void addLineObjectBetweenRelationItem(List<String> source, String dest, List<RangeObj> middleObj) {
        RelationItem sourceItem = findRelationItem(source, dest);
        buildExtendChainCheck(sourceItem, middleObj);
        removeRelationItemInner(sourceItem);
        RelationInstance instance = buildLineExtendChain(sourceItem, middleObj);
        addInstance(instance);
    }

    @Override
    public void addObjectBetweenRelationItem(String source, String dest, List<RangeObj> middleObj) {
        RelationItem sourceItem = findRelationItem(Ls.of(source), dest);
        removeRelationItemInner(sourceItem);
        RelationInstance instance = buildExtendChain(sourceItem, middleObj);
        addInstance(instance);
    }

    public void addInstance(List<RelationItem> addList) {
        addList = addList.stream().map(RelationItem::clone).collect(Collectors.toList());
        addList.forEach(this::transferToLocatorName);
        addInstanceInner(addList);
    }

    private void addInstanceInner(List<RelationItem> addList) {
        RelationInstance instance = new RelationInstance("-");
        instance.setRelationItems(addList);
        for (RelationItem relationItem : addList) {
            relationItem.setParentInstance(instance);
        }
        addInstance(instance);
    }

    private RelationInstance buildExtendChain(RelationItem sourceItem, List<RangeObj> middleObj) {
        RelationInstance instance = new RelationInstance("-");
        List<RelationItem> itemList = new ArrayList<>();
        List<RangeObj> sourceLs = sourceItem.getSourceObjectList();
        RangeObj destObject = sourceItem.getDestObject();

        List<RangeObj> newSource = new ArrayList<>();

        for (RangeObj rangeObj : middleObj) {
            String objId = addConcept(rangeObj.getObjectName());
            RangeObj reName = rangeObj.withOtherName(objId);
            newSource.add(reName);
            RelationItem newItem = new RelationItem();
            newItem.setSourceObjectList(sourceLs);
            newItem.setDestObject(reName);
            newItem.setParentInstance(instance);
            itemList.add(newItem);
        }

        RelationItem newItem = new RelationItem();
        newItem.setSourceObjectList(newSource);
        newItem.setDestObject(destObject);
        newItem.setParentInstance(instance);
        itemList.add(newItem);
        instance.setRelationItems(itemList);
        return instance;
    }

    private void buildExtendChainCheck(RelationItem sourceItem, List<RangeObj> middleObj) {
        Range destRange = sourceItem.getDestObject().getRange();
        List<Range> addRange = middleObj.stream().map(RangeObj::getRange).collect(Collectors.toList());
        addRange.add(destRange);
        Range result = Range.multi(addRange);
        if (!result.equals(destRange)) {
            throw new IllegalArgumentException(String.format(" 原有关系 %s，现在的关系 %s，数量关系错误", destRange, result));
        }
    }

    private RelationInstance buildLineExtendChain(RelationItem sourceItem, List<RangeObj> middleObj) {
        RelationInstance instance = new RelationInstance("-");
        List<RelationItem> itemList = new ArrayList<>();
        List<RangeObj> sourceLs = sourceItem.getSourceObjectList();
        RangeObj destObject = sourceItem.getDestObject();

        for (RangeObj rangeObj : middleObj) {
            String objId = addConcept(rangeObj.getObjectName());
            RangeObj reName = rangeObj.withOtherName(objId);
            RelationItem newItem = new RelationItem();
            newItem.setSourceObjectList(sourceLs);
            newItem.setDestObject(reName);
            newItem.setParentInstance(instance);
            sourceLs = Ls.of(RangeObj.one(reName.getObjectName()));
            itemList.add(newItem);
        }

        RelationItem newItem = new RelationItem();
        newItem.setSourceObjectList(sourceLs);
        newItem.setDestObject(destObject);
        newItem.setParentInstance(instance);
        itemList.add(newItem);
        instance.setRelationItems(itemList);
        return instance;
    }

    @Override
    public List<RelationChain> findAllRelationChain(List<String> sourceObjList, String destObj) {
        sourceObjList = sourceObjList.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException();
        }
        destObj = getObjUniqueId(destObj);
        List<RelationChain> relationChainListV2 = getRelationChainListV2(sourceObjList, destObj, getLastVersion());
        transferToRawName(relationChainListV2);
        return relationChainListV2;
    }

    @Override
    public List<RelationChain> findExactRelationChain(List<String> sourceObjList, String destObj) {
        List<RelationChain> relationChains = buildExactRelationChainWithoutTrans(sourceObjList, destObj);
        transferToRawName(relationChains);
        return relationChains;
    }

    private List<RelationChain> buildExactRelationChainWithoutTrans(List<String> sourceObjList, String destObj) {
        if (sourceObjList == null) {
            throw new IllegalArgumentException();
        }
        sourceObjList = sourceObjList.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException();
        }
        destObj = getObjUniqueId(destObj);
        List<RelationChain> relationChains = buildExactRelationChainInner(sourceObjList, destObj);
        return relationChains;
    }

    private List<RelationChain> buildExactRelationChainInner(List<String> sourceObjList, String destObj) {
        if (sourceObjList == null) {
            throw new IllegalArgumentException();
        }
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException();
        }
        return buildExactlyRelationChain(sourceObjList, destObj, new HashMap<>(), new HashMap<>(), getLastVersion());
    }

    @Override
    public List<RelationChain> findAllRelationChain(int version, List<String> sourceObjList, String destObj) {
        sourceObjList = sourceObjList.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException();
        }
        destObj = getObjUniqueId(destObj);
        List<RelationChain> relationChainListV2 = getRelationChainListV2(sourceObjList, destObj, version);
        transferToRawName(relationChainListV2);
        return relationChainListV2;
    }

    @Override
    public List<RelationChain> findExactRelationChain(int version, List<String> sourceObjList, String destObj) {
        if (sourceObjList == null) {
            throw new IllegalArgumentException();
        }
        sourceObjList = sourceObjList.stream().map(this::getObjUniqueId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException();
        }
        destObj = getObjUniqueId(destObj);
        List<RelationChain> relationChains = buildExactlyRelationChain(sourceObjList, destObj, new HashMap<>(), new HashMap<>(), version);

        transferToRawName(relationChains);
        return relationChains;
    }

    /**
     * 对于重复名称事物的智能搜索随后再支持，先支持不重复的搜索
     *
     * @param sourceObj
     * @param destObj
     * @return
     */
    @Override
    public RelationChain findChainByLocatorNode(List<BaseNode> sourceObj, RangeObj destObj) {
        return findChainByLocatorNode(sourceObj, destObj, getLastVersion());
    }

    @Override
    public RelationChain findChainByLocatorNode(List<BaseNode> sourceObj, RangeObj destObj, int version) {
        if (CollectionUtils.isEmpty(sourceObj)) {
            throw new IllegalArgumentException();
        }
        List<BaseNode> all = new ArrayList<>(sourceObj);
        all.add(new ParamNode(destObj));
        List<RelationItem> allRelationItems = new ArrayList<>();
        List<List<BaseNode>> splitNodeList = splitNodeList(all);

        for (List<BaseNode> nodeList : splitNodeList) {

            List<BaseNode> req = nodeList.subList(0, nodeList.size() - 1);
            List<String> lastSourceReqList = getAllSource(nodeList);
            BaseNode destNode = nodeList.get(nodeList.size() - 1);
            String dest = getObjUniqueId(destNode.getNodeName());

            List<RelationChain> relationChains = buildExactlyRelationChain(lastSourceReqList, dest,
                    new HashMap<>(), new HashMap<>(), version);

            if (CollectionUtils.isEmpty(relationChains)) {
                throw new RuntimeException(String.format("不存在从[%s]到[%s]的路径", req.stream().map(BaseNode::getNodeName)
                        .collect(Collectors.joining(",")), destNode.getNodeName()));
            }
            if (relationChains.size() == 1) {
                RelationChain relationChain = relationChains.get(0);
                List<RelationItem> relationItems1 = relationChain.getRelationItems();
                allRelationItems.addAll(relationItems1);
                continue;
            }
            if (relationChains.size() > 1) {
                throw new RuntimeException(String.format("从[%s]到[%s]的路径存在多条", req.stream().map(BaseNode::getNodeName)
                        .collect(Collectors.joining(",")), destNode.getNodeName()));
            }
        }
        List<String> allParamNode = getAllParamNode(all);
        RelationChain from = from(allParamNode, destObj.getObjectName(), allRelationItems, new HashMap<>(), new HashMap<>(), getLastVersion());
        transferToRawName(Ls.of(from));
        return from;
    }

    @Override
    public List<RelationChain> findAllRelationChain(List<RangeObj> sourceObj, RangeObj destObj) {
        List<RelationChain> chains = findAllRelationChain(sourceObj.stream().map(RangeObj::getObjectName).collect(Collectors.toList()), destObj.getObjectName());
        return chains.stream().filter(c -> filterByRange(sourceObj, destObj, c)).collect(Collectors.toList());
    }

    private boolean filterByRange(List<RangeObj> sourceObj, RangeObj destObj, RelationChain chains) {
        Map<String, RangeObj> rangeObjMap = sourceObj.stream().collect(Collectors.toMap(RangeObj::getObjectName, Function.identity()));
        RelationItem relationItem = chains.toRelationItem();
        for (RangeObj rangeObj : relationItem.getSourceObjectList()) {
            if (!rangeObjMap.containsKey(rangeObj.getObjectName())) {
                continue;
            }
            RangeObj rangeObj1 = rangeObjMap.get(rangeObj.getObjectName());
            if (!rangeObj.match(rangeObj1)) {
                return false;
            }
        }
        return relationItem.getDestObject().match(destObj);
    }

    @Override
    public List<RelationChain> findExactRelationChain(List<RangeObj> sourceObj, RangeObj destObj) {
        List<RelationChain> chains = findExactRelationChain(sourceObj.stream().map(RangeObj::getObjectName).collect(Collectors.toList()), destObj.getObjectName());
        return chains.stream().filter(c -> filterByRange(sourceObj, destObj, c)).collect(Collectors.toList());
    }

    @Override
    public List<RelationChain> findAllRelationChain(List<RangeObj> sourceObj, RangeObj destObj, int version) {
        List<RelationChain> chains = findAllRelationChain(version, sourceObj.stream().map(RangeObj::getObjectName).collect(Collectors.toList()), destObj.getObjectName());
        return chains.stream().filter(c -> filterByRange(sourceObj, destObj, c)).collect(Collectors.toList());
    }

    @Override
    public List<RelationChain> findExactRelationChain(List<RangeObj> sourceObj, RangeObj destObj, int version) {
        List<RelationChain> chains = findExactRelationChain(version, sourceObj.stream().map(RangeObj::getObjectName).collect(Collectors.toList()), destObj.getObjectName());
        return chains.stream().filter(c -> filterByRange(sourceObj, destObj, c)).collect(Collectors.toList());
    }

    private List<String> getAllSource(List<BaseNode> nodeList) {
        if (nodeList.size() < 2) {
            throw new IllegalArgumentException();
        }
        List<String> result = new ArrayList<>();
        for (int i = 0; i < nodeList.size() - 1; i++) {
            String name = nodeList.get(i).getNodeName();
            String objUniqueId = getObjUniqueId(name);
            result.add(objUniqueId);
        }
        return result;
    }

    private List<String> getAllParamNode(List<BaseNode> sourceObj) {
        List<String> result = new ArrayList<>();
        for (BaseNode baseNode : sourceObj) {
            if (baseNode instanceof ParamNode) {
                result.add(getObjUniqueId(baseNode.getNodeName()));
            }
        }
        return result;
    }

    private List<List<BaseNode>> splitNodeList(List<BaseNode> sourceObj) {
        List<List<BaseNode>> result = new ArrayList<>();

        List<BaseNode> lastList = new ArrayList<>();
        for (BaseNode baseNode : sourceObj) {

            if (baseNode instanceof ParamNode) {
                lastList.add(baseNode);
                continue;
            }

            if (baseNode instanceof LocatorNode) {
                lastList.add(baseNode);
                result.add(lastList);

                lastList = new ArrayList<>();
                lastList.add(baseNode);
            }
        }
        if (!lastList.isEmpty()) {
            result.add(lastList);
        }
        return result;
    }

    @Override
    public List<String> findAllConnectByRelation(List<String> sourceObj, String relationName) {
        sourceObj = sourceObj.stream().map(this::getObjUniqueId).collect(Collectors.toList());

        List<String> result = new ArrayList<>();
        for (String name : sourceObj) {
            Map<String, List<RelationItem>> relationItemMap = fromObjRelation.getOrDefault(name, new HashMap<>());
            for (RelationItem value : relationItemMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList())) {
                Set<String> sourceLs = value.getSourceObjectList().stream().map(RangeObj::getObjectName).collect(Collectors.toSet());
                Set<String> currentSourceLs = new HashSet<>(sourceLs);
                if (!sourceLs.equals(currentSourceLs)) {
                    continue;
                }
                if (Objects.equals(relationName, value.getName())) {
                    result.add(getLocateExpress(value.getDestObject().getObjectName()));
                }
            }
        }
        return result;
    }

    private synchronized int getNewInstanceId() {
        return currentInstanceId++;
    }

    private RelationChain from(List<String> rawSource, String destObj, List<RelationItem> relationItems, Map<String, Set<String>> foundWay, Map<String, Set<String>> allSourceFoundWay, int version) {
        if (CollectionUtils.isEmpty(relationItems)) {
            return null;
        }
        RelationChain chain = new RelationChain();
        List<RangeObj> requireList = new ArrayList<>();
        List<RangeObj> beforePathGetObj = new ArrayList<>();

        Set<String> allDestList = new HashSet<>();

        Map<RelationItem, RelationItem> breakPointInfo = new HashMap<>();

        List<RelationItem> sourceCalChain = new ArrayList<>();
        for (RelationItem relationItem : relationItems) {
            List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
            for (RangeObj goToObj : sourceObjectList) {

                // 当前的source 无法由上个item提供的提供提供
                if (beforePathGetObj.stream().noneMatch(re -> re.match(goToObj)) && beforePathGetObj.stream().noneMatch(re -> re.getObjectName().equals(goToObj.getObjectName()))) {
                    Set<String> allSource = requireList.stream().map(RangeObj::getObjectName).collect(Collectors.toSet());
                    allSource.addAll(rawSource);
                    allSource.addAll(beforePathGetObj.stream().map(RangeObj::getObjectName).collect(Collectors.toSet()));
                    //检查当前需要的事物 是否 已经被 提供的所蕴含进来了
                    RelationChain fromRawSource = getFromRawSource(new ArrayList<>(allSource), goToObj, relationItems, foundWay, allSourceFoundWay, version);
                    // 没有被蕴含进来
                    if (fromRawSource == null) {
                        if (!requireList.contains(goToObj)) {
                            requireList.add(goToObj);
                        }
                    } else {
                        if (!allDestList.contains(fromRawSource.toRelationItem().getDestObject().getObjectName())) {
                            // 发现 已经存在的source可以   推导出 这个 item的所需要的source
                            if (!sourceCalChain.isEmpty()) {
                                breakPointInfo.put(sourceCalChain.get(sourceCalChain.size() - 1).clone(), relationItem.clone());
                            }
                            List<RelationItem> items = fromRawSource.getRelationItems();
                            sourceCalChain.addAll(items);
                        }
                    }
                }
            }
            beforePathGetObj.add(relationItem.getDestObject());
            allDestList.add(relationItem.getDestObject().getObjectName());
            sourceCalChain.add(relationItem);
        }
        chain.setSourceObjectList(requireList.stream().map(RangeObj::clone).collect(Collectors.toList()));
        chain.setDestObject(relationItems.get(relationItems.size() - 1).getDestObject().clone());
        chain.setRelationItems(sourceCalChain.stream().map(RelationItem::clone).collect(Collectors.toList()));
        chain.setBreakPointInfo(breakPointInfo);
        chain.fixDestObjRange();
        chain.setVersion(version);
        return chain;
    }

    private Range getRange(List<RelationItem> relationItems) {
        Range result = ONE;
        String lastObject = null;
        for (RelationItem relationItem : relationItems) {
            if (result.equals(ONE)) {
                result = relationItem.getDestObject().getRange();
                lastObject = relationItem.getDestObject().getObjectName();
                continue;
            }
            if (isMulti(result)) {
                Range sourceObjectRange = relationItem.getSourceObjectRange(lastObject);
                Range destRange = relationItem.getDestObject().getRange();
                if (isMulti(sourceObjectRange)) {
                    result = destRange;
                }
                // note 其他情况range不变
            }
            lastObject = relationItem.getDestObject().getObjectName();
        }
        return result;
    }

    private RelationChain getFromRawSource(List<String> rawSource, RangeObj goToObj, List<RelationItem> relationItems, Map<String, Set<String>> foundWay, Map<String, Set<String>> allSourceFoundWay, int version) {
        if (rawSource.contains(goToObj.getObjectName())) {
            return null;
        }
        List<RelationChain> relationChainLs = new ArrayList<>();
        RelationChain result = null;
        int maxLength = Integer.MAX_VALUE;
        boolean one = goToObj.getRange().equals(ONE);
        for (String raw : rawSource) {
            if (foundWay.get(raw) != null && foundWay.get(raw).contains(goToObj.getObjectName())) {
                continue;
            }
            foundWay.computeIfAbsent(raw, k -> new HashSet<>());
            foundWay.get(raw).add(goToObj.getObjectName());
            List<RelationChain> relationChains = buildExactlyRelationChain(Ls.of(raw), goToObj.getObjectName(), foundWay, allSourceFoundWay, version);
            if (CollectionUtils.isNotEmpty(relationChains)) {
                relationChainLs.addAll(relationChains);
            }
        }
        for (RelationChain chain : relationChainLs) {
            boolean multi = isMulti(getRange(chain.getRelationItems()));
            if (one && multi) {
                continue;
            }
            if (chain.getRelationItems().size() < maxLength) {
                result = chain;
                maxLength = chain.getRelationItems().size();
            }
        }
        return result;
    }

    /**
     * @param relationChain
     * @param source
     * @return
     */
    private boolean hasAllSource(RelationChain relationChain, List<String> source) {
        if (relationChain.getSourceObjectList().size() != source.size()) {
            return false;
        }
        for (RangeObj sourRangeObj : relationChain.getSourceObjectList()) {
            if (source.contains(sourRangeObj.getObjectName())) {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * @param sourceObjList
     * @param destObj
     * @param version
     * @return
     */
    private List<RelationChain> getRelationChainListV2(List<String> sourceObjList, String destObj, int version) {
        Set<String> allSource = new HashSet<>(sourceObjList);
        String sourceObj = sourceObjList.get(0);
        List<RelationChain> result = new ArrayList<>();
        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.get(sourceObj);
        if (relationItemMap == null) {
            return new ArrayList<>();
        }
        for (Map.Entry<String, List<RelationItem>> itemEntry : relationItemMap.entrySet()) {
            for (RelationItem item : itemEntry.getValue()) {
                if (item.getVersion() > version) {
                    continue;
                }
                List<RelationItem> items = new ArrayList<>();
                if (itemEntry.getKey().equals(destObj)) {
                    items.add(item);
                    RelationChain from = from(sourceObjList, destObj, items, new HashMap<>(), new HashMap<>(), version);
                    result.add(from);
                    continue;
                }
                if (allSource.contains(item.getDestObj())) {
                    continue;
                }
                Set<String> found = new HashSet<>(getExceptRelationStr(item));
                List<List<RelationItem>> relationItems = buildRelationChainV2(allSource, found, itemEntry.getKey(), destObj, version);
                if (relationItems != null && !relationItems.isEmpty()) {
                    for (List<RelationItem> relationItem : relationItems) {
                        List<RelationItem> tempList = new ArrayList<>();
                        tempList.add(item);
                        tempList.addAll(relationItem);
                        RelationChain from = from(sourceObjList, destObj, tempList, new HashMap<>(), new HashMap<>(), version);
                        result.add(from);
                    }
                }
            }
        }
        result = removeRepeat(sourceObj, result);
        return result;
    }

    private List<RelationChain> getRelationChainWithoutError(List<String> sourceObjList, String destObj, int version) {
        String sourceObj = sourceObjList.get(0);
        List<RelationChain> result = new ArrayList<>();
        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.get(sourceObj);
        if (relationItemMap == null) {
            return new ArrayList<>();
        }

        Set<String> allSource = new HashSet<>(sourceObjList);

        for (Map.Entry<String, List<RelationItem>> itemEntry : relationItemMap.entrySet()) {
            for (RelationItem item : itemEntry.getValue()) {
                List<RelationItem> items = new ArrayList<>();
                if (itemEntry.getKey().equals(destObj)) {
                    items.add(item);
                    RelationChain from = from(sourceObjList, destObj, items, new HashMap<>(), new HashMap<>(), version);
                    result.add(from);
                    continue;
                }
                if (allSource.contains(item.getDestObj())) {
                    continue;
                }
                Set<String> found = new HashSet<>(getExceptRelationStr(item));
                List<List<RelationItem>> relationItems = buildRelationChainV2(allSource, found, itemEntry.getKey(), destObj, getLastVersion());
                if (relationItems != null && !relationItems.isEmpty()) {
                    for (List<RelationItem> relationItem : relationItems) {
                        List<RelationItem> tempList = new ArrayList<>();
                        tempList.add(item);
                        tempList.addAll(relationItem);
                        RelationChain from = from(sourceObjList, destObj, tempList, new HashMap<>(), new HashMap<>(), version);
                        result.add(from);
                    }
                }
            }
        }
        result = removeRepeat(sourceObj, result);
        List<RelationChain> afterFilter = result.stream().filter(Objects::nonNull).filter(re -> hasAllSource(re, sourceObjList)).collect(Collectors.toList());
        return afterFilter;
    }

    private Set<String> getExceptRelationStr(RelationItem item) {
        Set<String> result = new HashSet<>();
        String destName = item.getDestObject().getObjectName();
        for (RangeObj rangeObj : item.getSourceObjectList()) {
            result.add(String.format("%s->%s", destName, rangeObj.getObjectName()));
            result.add(String.format("%s->%s", rangeObj.getObjectName(), destName));
        }
        return result;
    }

    private Set<String> getForward(RelationItem item) {
        String destName = item.getDestObject().getObjectName();
        Set<String> result = new HashSet<>();
        for (RangeObj rangeObj : item.getSourceObjectList()) {
            result.add(String.format("%s->%s", rangeObj.getObjectName(), destName));
        }
        return result;
    }

    private List<RelationChain> buildExactlyRelationChain(List<String> sourceObjList, String destObj, Map<String, Set<String>> foundWay, Map<String, Set<String>> allSourceFoundWay, int version) {
        if (sourceObjList.size() == 1 && sourceObjList.get(0).equals(destObj)) {
            RelationItem relationItem = new RelationItem();
            relationItem.setSourceObjectList(Ls.of(RangeObj.one(sourceObjList.get(0))));
            relationItem.setDestObject(RangeObj.one(destObj));
            RelationChain relationChain = from(sourceObjList, destObj, Ls.of(relationItem), foundWay, new HashMap<>(allSourceFoundWay), version);
            return Ls.of(relationChain);
        }
        if (CollectionUtils.isEmpty(sourceObjList)) {
            throw new IllegalArgumentException();
        }
        String sourceObj = sourceObjList.get(0);
        List<RelationChain> result = new ArrayList<>();
        if (!objectInfoMap.containsKey(sourceObj)) {
            throw new IllegalArgumentException(String.format("不存在名为%s的事物", sourceObj));
        }

        Set<String> allSource = new HashSet<>(sourceObjList);

        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.get(sourceObj);
        if (relationItemMap == null) {
            return new ArrayList<>();
        }
        for (Map.Entry<String, List<RelationItem>> itemEntry : relationItemMap.entrySet()) {
            for (RelationItem item : itemEntry.getValue()) {
                List<RelationItem> items = new ArrayList<>();
                if (itemEntry.getKey().equals(destObj)) {
                    items.add(item);
                    RelationChain from = from(sourceObjList, destObj, items, foundWay, new HashMap<>(allSourceFoundWay), version);
                    result.add(from);
                    continue;
                }
                if (allSource.contains(item.getDestObj())) {
                    continue;
                }
                Set<String> found = new HashSet<>(getExceptRelationStr(item));
                List<List<RelationItem>> relationItems = buildRelationChainV2(allSource, found, itemEntry.getKey(), destObj, version);
                if (relationItems != null && !relationItems.isEmpty()) {
                    for (List<RelationItem> relationItem : relationItems) {
                        List<RelationItem> tempList = new ArrayList<>();
                        tempList.add(item);
                        tempList.addAll(relationItem);
                        RelationChain from = from(sourceObjList, destObj, tempList, foundWay, new HashMap<>(allSourceFoundWay), version);
                        result.add(from);
                    }
                }
            }
        }
        result = removeRepeat(sourceObj, result);
        List<RelationChain> chainList = result.stream().filter(Objects::nonNull).filter(re -> hasAllSource(re, sourceObjList)).collect(Collectors.toList());
        return chainList;
    }

    private List<List<RelationItem>> buildRelationChainV2(Set<String> allSource, Set<String> found, String sourceObj, String destObj, int version) {
        if (!fromObjRelation.containsKey(sourceObj)) {
            return null;
        }
        List<List<RelationItem>> result = new ArrayList<>();

        Map<String, List<RelationItem>> relationItemMap = fromObjRelation.get(sourceObj);
        for (Map.Entry<String, List<RelationItem>> itemEntry : relationItemMap.entrySet()) {
            for (RelationItem item : itemEntry.getValue()) {

                if (item.getVersion() > version) {
                    continue;
                }
                Set<String> forwardStr = getForward(item);
                if (forwardStr.stream().anyMatch(found::contains)) {
                    continue;
                }
                List<RelationItem> items = new ArrayList<>();
                if (itemEntry.getKey().equals(destObj)) {
                    items.add(item);
                    result.add(items);
                    continue;
                }
                if (allSource.contains(item.getDestObj())) {
                    continue;
                }
                Set<String> tempFound = new HashSet<>(found);
                tempFound.addAll(getExceptRelationStr(item));
                List<List<RelationItem>> relationItems = buildRelationChainV2(allSource, tempFound, itemEntry.getKey(), destObj, version);
                if (relationItems != null && !relationItems.isEmpty()) {
                    for (List<RelationItem> relationItem : relationItems) {
                        List<RelationItem> tempList = new ArrayList<>();
                        tempList.add(item);
                        tempList.addAll(relationItem);
                        result.add(tempList);
                    }
                }
            }
        }
        return result;
    }

    private void transferToRawName(List<RelationChain> relationChainListV2) {
        for (RelationChain relationChain : relationChainListV2) {
            relationChain.getRelationItems().forEach(this::transferToRawName);
            relationChain.getSourceObjectList().forEach(this::setToRawName);
            setToRawName(relationChain.getDestObject());

            Map<RelationItem, RelationItem> breakPointInfo = relationChain.getBreakPointInfo();
            Map<RelationItem, RelationItem> changeName = new HashMap<>();

            for (Map.Entry<RelationItem, RelationItem> itemEntry : breakPointInfo.entrySet()) {
                RelationItem key = itemEntry.getKey().clone();
                RelationItem vale = itemEntry.getValue().clone();
                transferToRawName(key);
                transferToRawName(vale);
                changeName.put(key, vale);
            }
            relationChain.setBreakPointInfo(changeName);
        }
    }

    private void transferToRawNameInstance(List<RelationInstance> relationChainListV2) {
        for (RelationInstance instance : relationChainListV2) {
            instance.getRelationItems().forEach(this::transferToRawName);
        }
    }

    private String getUniqueObjName(String objName) {
        return objName + "_" + currentObjectId.incrementAndGet();
    }

    private void setToRawName(RangeObj rangeObj) {
        rangeObj.setObjectName(getLocateExpress(rangeObj.getObjectName()));
    }

    private void setToLocatorName(RangeObj rangeObj) {
        rangeObj.setObjectName(getObjUniqueId(rangeObj.getObjectName()));
    }

    private RelationItem transferToRawName(RelationItem item) {
        item.getSourceObjectList().forEach(this::setToRawName);
        setToRawName(item.getDestObject());
        return item;
    }

    private void transferToLocatorName(RelationItem item) {
        item.getSourceObjectList().forEach(this::setToLocatorName);
        setToLocatorName(item.getDestObject());
    }

    private List<RelationChain> buildAllRelationChainInner(List<String> sourceObjList, String destObj) {
        return getRelationChainListV2(sourceObjList, destObj, getLastVersion());
    }

}
